﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;

namespace TestOption
{
    /// <summary>
    /// IOptions单例，改变了就全局改变
    /// IOptionsMonitor 可以通过代码和配置文件改变（同一作用域数据可能不一样：在作用域获取数据过程中，配置文件更改，结果也会同时更改）
    /// IOptionsSnapshot 无法通过代码改变，始终为最新的配置文件（同一作用域数据一样）
    /// 参考资料地址：https://www.cnblogs.com/wenhx/p/ioptions-ioptionsmonitor-and-ioptionssnapshot.html
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder();
            builder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); //注意最后一个参数值，true表示配置文件更改时会重新加载。
            var configuration = builder.Build();
            var services = new ServiceCollection();
            services.AddOptions();
            services.Configure<TestOptions>(configuration); //这里通过配置文件绑定TestOptions
            var provider = services.BuildServiceProvider();
            Console.WriteLine("修改前：");
            Print(provider);

            Change(provider); //使用代码修改Options值。
            Console.WriteLine("使用代码修改后：");
            Print(provider);

            Console.WriteLine("请修改配置文件。");
            Console.ReadLine(); //等待手动修改appsettings.json配置文件。
            Console.WriteLine("修改appsettings.json文件后：");
            Print(provider);
        }

        static void Print(IServiceProvider provider)
        {
            using (var scope = provider.CreateScope())
            {
                var sp = scope.ServiceProvider;
                var options1 = sp.GetRequiredService<IOptions<TestOptions>>();
                var options2 = sp.GetRequiredService<IOptionsMonitor<TestOptions>>();
                var options3 = sp.GetRequiredService<IOptionsSnapshot<TestOptions>>();
                Console.WriteLine("IOptions值: {0}", options1.Value.Name);
                Console.WriteLine("IOptionsMonitor值: {0}", options2.CurrentValue.Name);
                Console.WriteLine("IOptionsSnapshot值: {0}", options3.Value.Name);


                Console.WriteLine("是否在同一作用域中改变配置文件:请输入y或者n");
                var input = Console.ReadKey().Key.ToString();//你可以选择在此时更新配置文件
                if (input == "Y")
                {
                    Console.WriteLine();
                    var options1copy = sp.GetRequiredService<IOptions<TestOptions>>();
                    var options2copy = sp.GetRequiredService<IOptionsMonitor<TestOptions>>();
                    var options3copy = sp.GetRequiredService<IOptionsSnapshot<TestOptions>>();
                    Console.WriteLine("copyIOptions值: {0}", options1copy.Value.Name);
                    Console.WriteLine("copyIOptionsMonitor值: {0}", options2copy.CurrentValue.Name);
                    Console.WriteLine("copyIOptionsSnapshot值: {0}", options3copy.Value.Name);
                }

                Console.WriteLine();
            }
        }

        static void Change(IServiceProvider provider)
        {
            using (var scope = provider.CreateScope())
            {
                var sp = scope.ServiceProvider;
                sp.GetRequiredService<IOptions<TestOptions>>().Value.Name = "IOptions Test 1";
                sp.GetRequiredService<IOptionsMonitor<TestOptions>>().CurrentValue.Name = "IOptionsMonitor Test 1";
                sp.GetRequiredService<IOptionsSnapshot<TestOptions>>().Value.Name = "IOptionsSnapshot Test 1";
            }
        }
    }
}
